#include "stdafx.h"
#include "TextClass.h"


CTextClass::CTextClass(void) : m_pFont(nullptr), m_pFontShader(nullptr), m_pSentence1(nullptr), m_pSentence(nullptr), m_nScreenWidth(0), m_nScreenHeight(0)
{
}


CTextClass::~CTextClass(void)
{
}

bool CTextClass::SetMousePosition(int nXPos, int nYPos, ID3D11DeviceContext* pDeviceContext)
{
	char cTempString[16];
	char cMouseString[16];
	bool bResult;

	_itoa_s(nXPos, cTempString, 10);

	strcpy_s(cMouseString, "Mouse X: ");
	strcat_s(cMouseString, cTempString);

	bResult = UpdateSentence(m_pSentence, cMouseString, 20, 20, 1.0f, 1.0f, 1.0f, pDeviceContext);
	if(!bResult)
	{
		return false;
	}

	_itoa_s(nYPos, cTempString, 10);

	strcpy_s(cMouseString, "Mouse Y: ");
	strcat_s(cMouseString, cTempString);

	bResult = UpdateSentence(m_pSentence1, cMouseString, 20, 40, 1.0f, 1.0f, 1.0f, pDeviceContext);
	if(!bResult)
	{
		return false;
	}

	return true;
}

bool CTextClass::Initialize(ID3D11Device* pDevice, ID3D11DeviceContext* pDeviceContext, HWND hWnd, int nScreenWidth, int nScreenHeight, D3DXMATRIX d3dBaseViewMatrix)
{
	bool bResult = false;

	m_nScreenWidth = nScreenWidth;
	m_nScreenHeight = nScreenHeight;
	m_d3dBaseViewMatrix = d3dBaseViewMatrix;

	m_pFont = new CFontClass();
	if(m_pFont == nullptr)
	{
		DEBUG_OUTPUT("Failed to create text class font pointer");
		return false;
	}

	bResult = m_pFont->Initialize(pDevice, "../Resources/Font/FontData.txt", L"../Resources/DDS/Font.dds");
	if(bResult == false)
	{
		DEBUG_OUTPUT("Failed to initialize font object");
		return false;
	}

	m_pFontShader = new CFontShaderClass();
	if(m_pFontShader == nullptr)
	{
		DEBUG_OUTPUT("Failed to create text font shader pointer");
		return false;
	}

	bResult = m_pFontShader->Initialize(pDevice, hWnd);
	if(bResult == false)
	{
		DEBUG_OUTPUT("Failed to initialize text class font shader");
		return false;
	}

	bResult = InitializeSentence(&m_pSentence, 16, pDevice);
	if(bResult == false)
	{
		DEBUG_OUTPUT("Failed to initialize first sentence");
		return false;
	}

	bResult = UpdateSentence(m_pSentence, "Hello", 100, 100, 1.0f, 1.0f, 1.0f, pDeviceContext);
	if(bResult == false)
	{
		DEBUG_OUTPUT("Failed to update first sentence");
		return false;
	}

	bResult = InitializeSentence(&m_pSentence1, 16, pDevice);
	if(bResult == false)
	{
		DEBUG_OUTPUT("Failed to initialize second sentence");
		return false;
	}

	//bResult = UpdateSentence(m_pSentence1, "Goodbye", 100, 200, 1.0f, 1.0f, 0.0f, pDeviceContext);
	//if(bResult == false)
	//{
	//	DEBUG_OUTPUT("Failed to update second sentence");
	//	return false;
	//}

	return true;
}

void CTextClass::ShutDown()
{
	ReleaseSentence(&m_pSentence);
	ReleaseSentence(&m_pSentence1);

	if(m_pFontShader != nullptr)
	{
		m_pFontShader->ShutDown();
		delete m_pFontShader;
		m_pFontShader = nullptr;
	}

	if(m_pFont != nullptr)
	{
		m_pFont->ShutDown();
		delete m_pFont;
		m_pFont = nullptr;
	}
}

bool CTextClass::Render(ID3D11DeviceContext* pDeviceContext, D3DXMATRIX d3dWorld, D3DXMATRIX d3dOrtho)
{
	bool bResult = false;

	bResult = RenderSentence(pDeviceContext, m_pSentence, d3dWorld, d3dOrtho);
	if(bResult == false)
	{
		DEBUG_OUTPUT("Failed to render first sentence");
		return false;
	}

	bResult = RenderSentence(pDeviceContext, m_pSentence1, d3dWorld, d3dOrtho);
	if(bResult == false)
	{
		DEBUG_OUTPUT("Failed to render second sentence");
		return false;
	}

	return true;
}

bool CTextClass::InitializeSentence(SentenceType** pSentence, int nMaxLength, ID3D11Device* pDevice)
{
	VertexType* pVertices = nullptr;
	unsigned long* ulIndices = nullptr;
	D3D11_BUFFER_DESC stVertexBufferDesc;
	D3D11_BUFFER_DESC stIndexBufferDesc;
	D3D11_SUBRESOURCE_DATA pVertexData;
	D3D11_SUBRESOURCE_DATA pIndexData;
	HRESULT hResult;

	*pSentence = new SentenceType();
	if(*pSentence == nullptr)
	{
		DEBUG_OUTPUT("Failed to create sentence pointer");
		return false;
	}

	(*pSentence)->pVertexBuffer = 0;
	(*pSentence)->pIndexBuffer = 0;
	(*pSentence)->nMaxLength = nMaxLength;
	(*pSentence)->nVertexCount = 6 * nMaxLength;
	(*pSentence)->nIndexCount = (*pSentence)->nVertexCount;

	pVertices = new VertexType[(*pSentence)->nVertexCount];
	if(pVertices == nullptr)
	{
		DEBUG_OUTPUT("Failed to create text vertex pointer");
		return false;
	}

	ulIndices = new unsigned long[(*pSentence)->nIndexCount];
	if(ulIndices == nullptr)
	{
		DEBUG_OUTPUT("Failed to create text index pointer");
		return false;
	}

	memset(pVertices, 0, (sizeof(VertexType) * (*pSentence)->nVertexCount));

	for(int i = 0; i < (*pSentence)->nIndexCount; ++i)
	{
		ulIndices[i] = i;
	}

	stVertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
	stVertexBufferDesc.ByteWidth = sizeof(VertexType) * (*pSentence)->nVertexCount;
	stVertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	stVertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
	stVertexBufferDesc.MiscFlags = 0;
	stVertexBufferDesc.StructureByteStride = 0;

	pVertexData.pSysMem = pVertices;
	pVertexData.SysMemPitch = 0;
	pVertexData.SysMemSlicePitch = 0;

	hResult = pDevice->CreateBuffer(&stVertexBufferDesc, &pVertexData, &(*pSentence)->pVertexBuffer);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to create text vertex buffer");
		return false;
	}

	stIndexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	stIndexBufferDesc.ByteWidth = sizeof(unsigned long) * (*pSentence)->nIndexCount;
	stIndexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
	stIndexBufferDesc.CPUAccessFlags = 0;
	stIndexBufferDesc.MiscFlags = 0;
	stIndexBufferDesc.StructureByteStride = 0;

	pIndexData.pSysMem = ulIndices;
	pIndexData.SysMemPitch = 0;
	pIndexData.SysMemSlicePitch = 0;

	hResult = pDevice->CreateBuffer(&stIndexBufferDesc, &pIndexData, &(*pSentence)->pIndexBuffer);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to create text index buffer");
		return false;
	}

	delete[] pVertices;
	pVertices = nullptr;

	delete[] ulIndices;
	ulIndices = nullptr;

	return true;
}

bool CTextClass::UpdateSentence(SentenceType* pSentence, char* cText, int nXPos, int nYPos, float fRed, float fGreen, float fBlue, ID3D11DeviceContext* pDeviceContext)
{
	int nNumLetters;
	VertexType* pVertices;
	VertexType* pVertexPtr;
	float fDrawX;
	float fDrawY;
	D3D11_MAPPED_SUBRESOURCE stMappedResource;
	HRESULT hResult;

	pSentence->fRed = fRed;
	pSentence->fGreen = fGreen;
	pSentence->fBlue = fBlue;

	nNumLetters = (int)strlen(cText);

	if(nNumLetters > pSentence->nMaxLength)
	{
		return false;
	}

	pVertices = new VertexType[pSentence->nVertexCount];
	if(pVertices == nullptr)
	{
		DEBUG_OUTPUT("Failed to create new text class vertex pointer");
		return false;
	}

	memset(pVertices, 0, (sizeof(VertexType) * pSentence->nVertexCount));

	fDrawX = (float)(((m_nScreenWidth / 2) * -1) + nXPos);
	fDrawY = (float)((m_nScreenHeight / 2) - nYPos);

	m_pFont->BuildVertexArray((void*)pVertices, cText, fDrawX, fDrawY);

	hResult = pDeviceContext->Map(pSentence->pVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &stMappedResource);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to map text class vertex buffer");
		return false;
	}

	pVertexPtr = (VertexType*)stMappedResource.pData;

	memcpy(pVertexPtr, (void*)pVertices, (sizeof(VertexType) * pSentence->nVertexCount));

	pDeviceContext->Unmap(pSentence->pVertexBuffer, 0);

	delete[] pVertices;
	pVertices = nullptr;

	return true;
}

void CTextClass::ReleaseSentence(SentenceType** pSentence)
{
	if(*pSentence)
	{
		// Release the sentence vertex buffer.
		if((*pSentence)->pVertexBuffer)
		{
			(*pSentence)->pVertexBuffer->Release();
			(*pSentence)->pVertexBuffer = nullptr;
		}

		// Release the sentence index buffer.
		if((*pSentence)->pIndexBuffer)
		{
			(*pSentence)->pIndexBuffer->Release();
			(*pSentence)->pIndexBuffer = nullptr;
		}

		// Release the sentence.
		delete *pSentence;
		*pSentence = nullptr;
	}
}

bool CTextClass::RenderSentence(ID3D11DeviceContext* pDeviceContext, SentenceType* pSentence, D3DXMATRIX d3dWorld, D3DXMATRIX d3dOrtho)
{
	unsigned int nStride = sizeof(VertexType);
	unsigned int nOffset = 0;
	D3DXVECTOR4 d3dPixelColor;
	bool bResult = false;

	pDeviceContext->IASetVertexBuffers(0, 1, &pSentence->pVertexBuffer, &nStride, &nOffset);
	pDeviceContext->IASetIndexBuffer(pSentence->pIndexBuffer, DXGI_FORMAT_R32_UINT, 0);
	pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	d3dPixelColor = D3DXVECTOR4(pSentence->fRed, pSentence->fGreen, pSentence->fBlue, 1.0f);

	bResult = m_pFontShader->Render(pDeviceContext, pSentence->nIndexCount, d3dWorld, m_d3dBaseViewMatrix, d3dOrtho, m_pFont->GetTexture(), d3dPixelColor);
	if(bResult == false)
	{
		DEBUG_OUTPUT("Failed to render text font shader");
		return false;
	}

	return true;
}

bool CTextClass::SetFPS(int nFPS, ID3D11DeviceContext* pDeviceContext)
{
	char cTempString[16];
	char cFPSString[16];
	float fRed;
	float fGreen;
	float fBlue;
	bool bResult;

	if(nFPS > 9999)
	{
		nFPS = 9999;
	}

	_itoa_s(nFPS, cTempString, 10);

	strcpy_s(cFPSString, "Fps: ");
	strcat_s(cFPSString, cTempString);

	if(nFPS >= 60)
	{
		fRed = 0.0f;
		fGreen = 1.0f;
		fBlue = 0.0f;
	}

	if(nFPS < 60)
	{
		fRed = 1.0f;
		fGreen = 1.0f;
		fBlue = 0.0f;
	}

	if(nFPS < 30)
	{
		fRed = 1.0f;
		fGreen = 0.0f;
		fBlue = 0.0f;
	}

	bResult = UpdateSentence(m_pSentence, cTempString, 20, 20, fRed, fGreen, fBlue, pDeviceContext);
	if(!bResult)
	{
		DEBUG_OUTPUT("Failed to set the fps");
		return false;
	}

	return true;
}

bool CTextClass::SetCPU(int nCPU, ID3D11DeviceContext* pDeviceContext)
{
	char cTempString[16];
	char cCPUString[16];
	bool bResult;

	_itoa_s(nCPU, cTempString, 10);

	strcpy_s(cCPUString, "Cpu: ");
	strcat_s(cCPUString, cTempString);
	strcat_s(cCPUString, "%");

	bResult = UpdateSentence(m_pSentence1, cCPUString, 20, 40, 0.0f, 1.0f, 0.0f, pDeviceContext);
	if(!bResult)
	{
		DEBUG_OUTPUT("Failed to set the cpu percentage");
		return false;
	}
	return true;
}

bool CTextClass::SetRenderCount(int nRenderCount, ID3D11DeviceContext* pDeviceContext)
{
	char cTempString[32];
	char cCountString[32];
	bool bResult;

	_itoa_s(nRenderCount, cTempString, 10);

	strcpy_s(cCountString, "Render Count: ");
	strcat_s(cCountString, cTempString);

	bResult = UpdateSentence(m_pSentence, cCountString, 20, 20, 1.0f, 1.0f, 1.0f, pDeviceContext);
	if(bResult == false)
	{
		DEBUG_OUTPUT("Failed to update sentence");
		return false;
	}

	return true;
}
